package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.common.enums.CachePrefix;
import com.tcm.entity.LearningTime;
import com.tcm.entity.bo.UserCacheBo;
import com.tcm.entity.vo.LearningTimeStatisticResp;
import com.tcm.exception.DatabaseOperationException;
import com.tcm.service.LearningTimeService;
import com.tcm.mapper.LearningTimeMapper;
import com.tcm.utils.DateTimeUtil;
import com.tcm.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 学生学习时长业务实现
* @author Guqier
* @description 针对表【ts_learning_time(学生每日学习时长记录表)】的数据库操作Service实现
* @createDate 2023-08-23 18:11:01
*/
@Service
public class LearningTimeServiceImpl extends ServiceImpl<LearningTimeMapper, LearningTime>
    implements LearningTimeService{

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 保存学习时长
     * @param seconds 时长，单位秒
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功
     */
    @Override
    @Transactional
    public boolean saveStuLearningTime(Integer seconds, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询当前学生的最新一条学习记录
        LambdaQueryWrapper<LearningTime> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningTime::getAccount, userCacheBo.getAccount());
        queryWrapper.orderByDesc(LearningTime::getUpdateTime);
        queryWrapper.last("limit 1");
        LearningTime learningTime = this.getOne(queryWrapper);
        boolean flag;
        if (learningTime == null) {
            LearningTime time = new LearningTime();
            time.setAccount(userCacheBo.getAccount());
            time.setDate(new Date());
            time.setTime(seconds);
            time.setCreateUser(currUserId);
            time.setUpdateUser(currUserId);
            flag = this.save(time);
        }else {
            // 获取记录时间
            Date date = learningTime.getDate();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            // 获取当前时间
            Calendar nowCalendar = Calendar.getInstance();
            nowCalendar.setTime(new Date());
            // 判断记录是否是当天
            if (calendar.get(Calendar.YEAR) == nowCalendar.get(Calendar.YEAR) && calendar.get(Calendar.MONTH) == nowCalendar.get(Calendar.MONTH) && calendar.get(Calendar.DAY_OF_MONTH) == nowCalendar.get(Calendar.DAY_OF_MONTH)){
                learningTime.setTime(learningTime.getTime() + seconds);
                learningTime.setUpdateUser(currUserId);
                flag = this.updateById(learningTime);
            }else {
                LearningTime time = new LearningTime();
                time.setAccount(userCacheBo.getAccount());
                time.setDate(new Date());
                time.setTime(seconds);
                time.setCreateUser(currUserId);
                time.setUpdateUser(currUserId);
                flag = this.save(time);
            }
        }
        if (!flag){
            throw new DatabaseOperationException("数据库操作失败");
        }
        return true;
    }

    /**
     * 获取一周内学习时长统计
     * @param currUserId 当前用户ID
     * @return 一周内学习时长统计
     */
    @Override
    public LearningTimeStatisticResp getLearningTimeOfWeek(Long currUserId){
        return getLearningTimeResp(currUserId, 7);
    }

    /**
     * 获取一月内学习时长统计
     * @param currUserId 当前用户ID
     * @return 一周内学习时长统计
     */
    @Override
    public LearningTimeStatisticResp getLearningTimeOfMonth(Long currUserId){
        return getLearningTimeResp(currUserId, 30);
    }

    /**
     * 获取指定天数学习时长统计
     * @param currUserId 当前登录用户ID
     * @param dayNum 指定天数
     * @return 学习时长统计
     */
    @Override
    public LearningTimeStatisticResp getLearningTimeResp(Long currUserId, Integer dayNum){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 获取学习时长记录
        List<LearningTime> learningTimes = getLearningTimeListByRange(userCacheBo.getAccount(), dayNum);
        // 查询学习总时长
        Integer total = this.getBaseMapper().selectTotalLearningTime(userCacheBo.getAccount());
        // 封装结果
        LearningTimeStatisticResp resp = new LearningTimeStatisticResp();
        resp.setTotalTime((Objects.nonNull(total) ? total : 0) / 60);
        resp.setAverageTime(learningTimes.stream().map(LearningTime::getTime).reduce(0, Integer::sum) / 60 / dayNum);
        learningTimes.stream().max(Comparator.comparing(LearningTime::getTime)).ifPresent(learningTime -> {
            resp.setMaxTime(learningTime.getTime() / 60);
            resp.setMaxDate(learningTime.getDate());
        });
        List<LearningTimeStatisticResp.DayTime> dayTimeList = new ArrayList<>();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        for (int i = 0; i < dayNum; i++) {
            // 获取时间
            calendar.setTime(new Date());
            calendar.add(Calendar.DATE, -i);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            Date time = calendar.getTime();
            Optional<LearningTime> optional = learningTimes.stream().filter(learningTime -> dateFormat.format(learningTime.getDate()).equals(dateFormat.format(time))).findFirst();
            if (optional.isPresent()) {
                LearningTime learningTime = optional.get();
                LearningTimeStatisticResp.DayTime dayTime = new LearningTimeStatisticResp.DayTime();
                dayTime.setDate(learningTime.getDate());
                dayTime.setTime(learningTime.getTime() / 60);
                dayTimeList.add(dayTime);
            }else {
                LearningTimeStatisticResp.DayTime dayTime = new LearningTimeStatisticResp.DayTime();
                dayTime.setDate(time);
                dayTime.setTime(0);
                dayTimeList.add(dayTime);
            }
        }
        resp.setDays(dayTimeList);
        return resp;
    }

    /**
     * 根据距今天数获取学习时长记录列表
     * @param account 学生账号
     * @param range 距今天数
     * @return 学习时长记录列表
     */
    @Override
    public List<LearningTime> getLearningTimeListByRange(String account, Integer range){
        // 查询N天记录
        // 获取当前最后时间
        Date endTime = DateTimeUtil.dayRange(range).getEndTime();
        // 获取N天前开始时间
        Date startTime = DateTimeUtil.dayRange(range).getStartTime();
        // 查询符合条件的记录
        LambdaQueryWrapper<LearningTime> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningTime::getAccount, account);
        queryWrapper.ge(LearningTime::getDate, startTime);
        queryWrapper.le(LearningTime::getDate, endTime);
        queryWrapper.orderByDesc(LearningTime::getDate);
        queryWrapper.last("limit " + range);
        return this.list(queryWrapper);
    }

}




